반응형

<enemy_clever>

- Laser 씬을 상속하여 새로운 씬 생성

- New Inherited Scene... > laser.tscn 

- 노드 이름을 laser_enemy로 변경하고, laser_enemy.tscn으로 저장

- sprite에 enemy_laser.png 지정

- shape에 rectangleShape2D 지정 후 Edit

- Extents: (4.5, 7) 지정

- vis_notifier의 Rect값 지정(x:-4.5, y:-7, w:9, h:14)

- 속도 (0,150) 지정

- 아래방향으로 이동하는지 테스트

- 원점으로 복귀시켜 놓음

 

<enemy_clever>

- 상속으로 새로운 씬 생성 > enemy.tscn 선택

- 노드 이름을 enemy_clever로 변경

- 다른 이름으로 저장하기 > enemy_clever.tscn으로 저장

- sprite에 enemy_clever.png 지정

- shape에서 Make Unique 지정하여 다른 노드에 영향받지 않도록 함

- Position2D노드를 추가하여 cannon으로 이름 변경하고,

- Pos를 (0, 16) 지정

- 속도 50 지정

- 속도를 x:50, y:50 지정

- 기존의 스크립트 제거

- 새로운 스크립트 생성

- enemy_clever.gd

 

- spawner_enemy.gd 스크립트 수정

- enemy_kamikaze, enemy_clever를 미리 불러와 배열로 저장

- utils.choose함수로 랜덤하게 선택하여 생성

반응형
반응형

<플레어>

- Flare 씬 생성

- sprite 노드 생성 후 이름을 flare로 변경

- flare 첫번째 이미지를 지정해줌

- 애니메이션 노드 추가 후 이름을 anim으로 변경, fade_out 애니메이션 추가

- 0초에서 flare 스프라이트의 Opacity 1로 하여 키를 추가 (Modulate의 Opacity속성을 255)

- 0.1초에서 Opacity 0으로 하여 키를 추가 (Modulate의 Opacity속성을 0)

- length를 0.1초로 변경

- flare sprite노드에 스크립트 추가(flare.gd)

 

 

<flare.gd>

시그널 "finished"은 "animation_finished"로 변경

 

<레이저>

- Laser 씬 생성(enemy용, player용 공통), Area2D 노드를 추가 후 laser로 변경

- Sprite, CollisionShape2D, VisibilityNotifier2D 노드를 추가하고, 아래와 같이 이름을 변경해준다.

- 세부 설정은 추후 상속 노드에서 할 예정이므로 더이상의 설정은 진행하지 않는다.

- laser노드에 스크립트 추가

extends Area2D

export var velocity = Vector2()
const scn_flare = preload("res://scenes/flare.tscn")

func _ready():
	set_process(true)
	create_flare()
    
	yield(get_node("vis_notifier"), "screen_exited")
	queue_free()
	pass
    
func _process(delta):
	translate(velocity * delta)
	pass
    
func create_flare():
	var flare = scn_flare.instance()
	flare.set_global_position(get_global_position())
	utils.main_node.add_child(flare)
	pass

 

- 상속으로 Player의 laser씬 만들기

- laser_ship.tscn으로 저장

- sprite에는 laser_ship.png 지정

- shape에는 rectangle, extends (3,6)

- vis_notifier에는 Rect w:6, h:12, x:-3, y:-6 으로 설정

- y속도: 350으로 설정

- laser_ship노드를 화면 중앙에 놓고 잘 실행되는지 확인

- Debugger > Remote Inspector에 보면 해당 노드가 사라졌음을 확인할 수 있다.

- 확인 후 원점으로 되돌려놓는다.

 

<Ship에 레이저 발사 구현하기>

- ship 노드를 불러와서 하위에 Node2D (cannons로 변경) 추가

- cannons노드 하위에 position2D(left로 변경) 추가

- cannons > Node2D > Transform > Pos에 (-12, -8) 입력하여 위치 수정

- left를 복사하여 right노드로 변경

- Pos값을 (12, -8)로 변경

- ship.gd 수정

반응형
반응형

2 타입의 Enemy 생성

Area2D 노드를 추가하여 enemy로 변경

- colisionShape2D 추가 > RectangleShape2D > Extents (16,16) 설정

- enemy 스크립트 추가

- y 속도 100으로 설정

- 화면을 넘어가면 삭제되도록 수정

 

- 첫번째 enemy: enemy_kamikaze

- sprite에 enemy_kamikaze 이미지를 불러옴

- CollisionShape2D에서 Make Unique를 설정하고, 사이즈를 12,16으로 변경

- 속도를 350으로 설정

- enemy spawn

- 자주 사용하는 함수를 utils.gd로 묶어서 스크립트 수정

# script: utils

extends Node

var main_node setget , _get_main_node
var view_size setget , _get_view_size
var mouse_pos setget , _get_mouse_pos

func _ready():
	pass

func create_timer(wait_time):
	var timer = Timer.new()
	timer.set_wait_time(wait_time)
	timer.set_one_shot(true)
	timer.connect("timeout", timer, "queue_free")
	add_child(timer)
	timer.start()
	return timer
	pass

func choose(choises):
	randomize()
	var rand_index = randi() % choises.size()
	return choises[rand_index]
	pass

func find_node(node):
	return self.main_node.find_node(node)
	pass

func attach(src_node, src_signal, trg_node, trg_func):
	if typeof(src_node) == TYPE_STRING:
		src_node = find_node(src_node)
	
	if typeof(trg_node) == TYPE_STRING:
		trg_node = find_node(trg_node)
	
	if src_node != null and trg_node != null:
		src_node.connect(src_signal, trg_node, trg_func)
	pass

func remote_call(src_node, method, arg0 = null, arg1 = null):
	src_node = find_node(src_node)
	
	if src_node and src_node.has_method(method):
		if arg0 and arg1:
			return src_node.call(method, arg0, arg1)
		if arg0:
			return src_node.call(method, arg0)
		
		return src_node.call(method)
	pass

func _get_mouse_pos():
	return get_viewport().get_mouse_pos()
	pass

func _get_main_node():
	var root = get_tree().get_root()
	return root.get_child( root.get_child_count()-1 )
	pass

func _get_view_size():
	return get_tree().get_root().get_visible_rect().size
	pass

- Project Settings > Autoload에 utils.gd 추가

- 수정된 함수 (계속 랜덤시기에 생성하는 부분 추가 while, yield)

- world씬에 추가

반응형
반응형

마우스 따라가는 동작 스크립팅

 

(수정..'2024.01.09) godot 버전 상승으로 get_pos()함수는 사용되지 않습니다. 그 외의 변경사항은 아래와 같습니다.

- get_pos() -->  get_global_pos()

- set_pos() -->  set_position()

- view_size.width --> view_size.x

extends Area2D 

func _ready():
	set_process(true)
	pass # Replace with function body.

func _process(delta):	
	var motion = (get_global_mouse_position().x - get_global_position().x) * 0.2
	translate(Vector2(motion, 0))
	
	var view_size = get_viewport_rect().size
	var pos = get_global_position()
	pos.x = clamp(pos.x, 0+16, view_size.x-16)
	set_position(pos)	
	pass

 

흐르는 별 배경화면 만들기

- 빈 노드를 추가하여 stars로 이름 변경

- sprite노드 추가하여 star_far_0로 이름 변경

- 이미지를 불러오고 Centered on을 해제

- star_far_0에 star.gd스크립트 붙이기

- 배경 이미지의 속도를 50으로 설정

- 배경을 다시 복사하여 위치를 0,0으로

- 배경을 다시 복사하여 위치를 0,+180으로

- 지금까지 만든것을 빈 노드를 하나 더 추가하여 stars_far로 이름짓고, 그 하위노드로 옮긴다.

- 이걸 통째로 복사하여 stars_close를 만들고 stars_close이미지로 바꿔 넣는다.

- world 씬에 stars씬을 추가하고, 위치를 상단으로 조정하여 화면 뒤쪽에 보이도록 한다.

- star_close의 Z값을 10정도로 하여, 우주선보다 위에 보이도록 설정한다.

 

반응형
반응형

이런거 한번 만들어보겠습니다.

(https://www.youtube.com/watch?v=Z9W6dlP-RB8&list=PLv3l-oZCXaqkUEqrLsKJIAhAxK_Im6Qew)

 

1. Project Settings

반응형
반응형

우분투 Gnome 런처?에서 보여지는 아이콘을 만들고자 합니다.

/usr/share/applications/ 폴도 안에 .desktop파일을 만들면 됩니다.

 

파일 내용은 아래와 같이 만듭니다.

[Desktop Entry]
Name=Defold
Type=Application
Terminal=False
Exec=/home/seaofcalm/Program_Install/Defold/Defold
Icon=/home/seaofcalm/.local/share/icons/hicolor/scalable/apps/defold.png

Type은 Application으로,

Terminal은 False로

Exec는 실제 실행파일 경로,

Icon은 아이콘 경로.....뭐...보면 알듯..

반응형
반응형


1. HUD Scene 추가

HUD는 Head Up Display의 약자인데 게임의 요소와는 상관없는 UI 작성을 위한 부분입니다. Scene을 하나 추가한 뒤 CanvasLayer노드를 추가합니다. HUD에서 표시할 내용으로는 Score, "Game Over" 또는 "Get Ready!" 같은 문구, "Start" 버튼입니다. 즉 레이블과 버튼 요소가 필요합니다. 아래의 노드들을 CanvasLayer노드 하위에 자식노드로 추가해줍니다.

 

  • ScoreLabel (Label)
  • Message (Label)
  • StartButton (Button)
  • MessageTimer (Timer)

2. 폰트

폰트를 추가합니다. 경로는 인스펙터 창에서 Control > Theme Overrides > Fonts > 새 DynamicFont를 선택하고, 한번 더 클릭하여 Font > Font Data부분에 dodge_assets > font에 있는 "Xolonium-Regular.ttf"폰트를 넣어줍니다.(드래그 앤 드랍)

Font > Settings > Size는 64로 설정합니다.

 

font >Dyna....의 아래쪽 화살표를 누르면 여러 메뉴가 나오고, "복사" 메뉴가 나옵니다. 이걸 누르면 복사가 가능한데, 만들어두었던 Message 라벨로 가서 동일한 위치에서 "붙여넣기"를 해주면 지금 했던 설정을 복사해 넣게됩니다.




3. 레이아웃

우선 ScoreLabel을 설정해보겠습니다. 상단 오른쪽에 나타나는 레이아웃을 선택하고 '위쪽 넓게'를 클릭합니다. 그리고 인스펙터 창에서는 Text: 0, Align: Center, Valign: Center로 설정해줍니다.

다음으로 Message 라벨을 수정해줍니다.

그리고 StartButton은 "Start"라고 텍스트를 입력하고, 레이아웃은 "아래쪽 중앙", Font도 복하를 해줍니다.

그리고나서  Margin속성에 Top: -200, Button: -100을 입력합니다.


MessageTimer노드에서 Wait Time을 2초로 설정해주고, One Shot속성을 "On"으로 합니다.

 

4. HUD.gd 스크립팅

start_game 시그널은 버튼이 눌렸을 때 Main노드에게 알려주는 시그널로 쓰일 예정입니다.

extends CanvasLayer

signal start_game


전달되는 메시지를 표시하기위한 함수를 작성합니다.

func show_message(text):
    $Message.text = text
    $Message.show()
    $MessageTimer.start()


Player가 충돌하여 죽었을 때 텍스트를 보여주는 함수를 아래와 같이 작성합니다.

func show_game_over():
    show_message("Game Over")
    # Wait until the MessageTimer has counted down.
    yield($MessageTimer, "timeout")

    $Message.text = "Dodge the\nCreeps!"
    $Message.show()
    # Make a one-shot timer and wait for it to finish.
    yield(get_tree().create_timer(1), "timeout")
    $StartButton.show()


그리고 시간이 변할때마다 Main 씬에의해 아래의 코드가 지속적으로 호출되어 점수(시간)을 증가시킵니다.

func update_score(score):
    $ScoreLabel.text = str(score)


그리고 MessageTimer의 timeout()시그널과, StartButton버튼의 pressed()시그널에 함수를 연결하겠습니다. 함수는 아래와 같이 작성해줍니다.

func _on_StartButton_pressed():
    $StartButton.hide()
    emit_signal("start_game")

func _on_MessageTimer_timeout():
    $Message.hide()


5. HUD를 Main에 연결

Main 씬에서 HUD를 불러와 연결하도록 하겠습니다.

Main 씬에서 HUD 씬(노드)를 선택하고, 노드탭으로 가면 연결할 수 있는 HUD의 시그널들이 나타납니다. 여기서 start_game시그널을 연결할 함수로 new_game()이라고 이름짓고 아래의 코드를 추가해줍니다.

$HUD.update_score(score)
$HUD.show_message("Get Ready")


game_over() 함수가 실행될 때 HUD에 표시되는 메시지를 실행하도록 아래 라인을 추가해줍니다.

$HUD.show_game_over()


_on_ScoreTimer_timeout() 함수에 아래 코드를 추가하여 점수 변경시 업데이트되도록 합니다.

$HUD.update_score(score)



6. 오래된 크리프 제거

아직은 Player가 죽고나서 다시 시작할 때 Mob들이 살아있습니다. 그래서 시작버튼을 누르면 전부 사라지도록 수정할 필요가 있습니다.

 

Mob 씬에서 루트노드를 선택하고 노드탭 > Groups탭 으로 갑니다. 그리고 이름을 "mobs"라고하여 Add버튼을 눌러 Mob들의 그룹을 지정합니다. 그리고는 game_over()함수에 아래의 코드를 추가합니다. 해당 그룹에 있는 객체들을 한번에 제거하는 명령입니다.

get_tree().call_group("mobs", "queue_free")

7. 마무리

Background

Main노드 최상단 자식노드로 ColorRect 노드를 추가한다. "Layout" -> "Full Rect" 으로 전체 화면 커버가 가능하다.TextureRect노드를 사용하면 이미지를 불러올 수도 있다.

Sound effects

Main신의 하위로 AudioStreamPlayer노드를 추가하고 이름을 Music이라고 변경합니다. 하나더 추가하여 DeathSound라고 이름을 변경합니다. Stream속성의 Load를 클릭하여 해당되는 오디오 파일을 지정해줍니다.
 
new_game()함수 아래 아래 코드를 추가합니다.
$Music.play()

game_over() 함수 아래 아래코드를 추가합니다.

$Music.stop()
$DeathSound.play()

Keyboard shortcut

HUD씬에서 StartButton을 클릭하고 Shortcut속성을 찾아서 "New Shortcut" > "Shortcut"을 클릭하면 두번째 속성이 나타납니다. "New InputEventAction">"InputEventAction"을 입력하면 Action속성이 나타나는데, ui_select라고 타이핑 입력합니다. 이게 스페이스바와 연동되는 지시어라고 합니다.

 

- 끝 -

 
반응형
반응형

1. Main Scene 생성

모든 요소들을 모을 Main Scene 을 생성합니다. 새 씬 생성후 "Node"라는 이름의 노드를 추가해줍니다.

그리고 "인스턴스화"아이콘을 클릭하여 Player.tscn을 불러옵니다.

그 외에는 자식노드 추가 기능에서 Timer 3개, Position2D 노드를 추가해주고, 각각의 이름을 아래와 같이 수정해줍니다.


MobTimer - 가장자리에서 Mob이 생성되는 시간 통제 (0.5초)
ScoreTimer - 매초마다 점수 증가시킴 (1.0초)
StartTimer - 시작하기 전에 지연 시간 부여 (2.0초)
StartPosition - Player의 시작 위치(240, 450)

2. Mob 생성

Main 노드가 Mob을 가장자리를 따라 랜덤한 위치에서 생성합니다. 이를 위해서는 Main 노드 하위에 Path2D 노드를 추가해줍니다. Path2D노드를 선택하면 아래와 같은 화면으로 변경되는데, 그 전에 "스마트 스냅 사용", "격자 스냅 사용" 을 클릭합니다. 그리고, 새로 생긴 Path관련 버튼 중 가운데 버튼(1: 점추가)을 누른다음 화면의 네 꼭지점을 시계방향(2~5)으로 클릭해줍니다. 마지막으로 마지막 버튼(6: 곡선닫기)을 클릭해주면 경로가 완성됩니다.


다음으로 PathFollow2D 노드를 Path2D노드 하위에 추가해줍니다. 이 노드는 Path를 따라서 어떤 작업을 해줍니다. 이 게임에서는 Mob 생성이겠죠?

그리고 각각의 이름을 MobPath, MobSpawnLocation으로 바꿔줍니다.

 


3. Main.gd 스크립팅

우선 아래의 코드로 시작하겠습니다.

extends Node

export (PackedScene) var Mob
var score

func _ready():
	randomize()

export (PackedScene) var Mob 구문으로 선언하면, 인스펙터 창에서 Mob이라는 속성이 나타나는 것을 확인할 수 있습니다. 여기에는 Scene을 넣어줄 수 있는데, 우리가 구성한 Mob.tscn을 넣어줍니다.(드래그 앤 드랍)

 

다음으로 Player가 Mob과 부딛혔을 때(hit signal) 게임오버를 나타내는 함수를 작성/연결하겠습니다. 조금 헷갈릴 수도 있는데요, Main Scene 하위에 있는 Player Scene을 선택(한번 클릭)하면, 우측의 "노드" 창에 시그널들이 나타납니다. 우리가 만든 hit 시그널도 보입니다. hit()시그널을 더블클릭하면 메서드 연결창이 나타납니다. 작성할 스크립트가 Main인 것을 확인하고, 받는 메서드의 이름을 game_over로 하여 "연결"을 클릭합니다.


추가되어야 하는 코드는 아래와 같습니다. new_game() 함수도 함께 작성합니다.

func game_over():
    $ScoreTimer.stop()
    $MobTimer.stop()

func new_game():
    score = 0
    $Player.start($StartPosition.position)
    $StartTimer.start()


다음으로 각 타이머와 연결된 함수를 만들겠습니다. 우선 StartTimer, ScoreTimer의 timeout() 시그널을 더블 클릭합니다.

각각의 함수는 아래와 같이 코딩합니다.

func _on_StartTimer_timeout():
    $MobTimer.start()
    $ScoreTimer.start()

func _on_ScoreTimer_timeout():
    score += 1

_on_StartTimer_timeout()함수에서는 MobTimer와 ScoreTimer가 시작되며,

_on_ScoreTimer_timeout()함수에서는 시간이 흐름에 따라 1점식 올라가게 될 것입니다.

 

MobTimer의 timeout()시그널을 더블클릭하여 연결함수를 생성합니다. _on_MobTimer_timeout()에서는 mob을(mob 인스턴스를) 생성할 것입니다.

func _on_MobTimer_timeout():
	# Choose a random location on Path2D.
    $MobPath/MobSpawnLocation.offset = randi()
    # Create a Mob instance and add it to the scene.
    var mob = Mob.instance()
    add_child(mob)
    # Set the mob's direction perpendicular to the path direction.
    var direction = $MobPath/MobSpawnLocation.rotation + PI / 2
    # Set the mob's position to a random location.
    mob.position = $MobPath/MobSpawnLocation.position
    # Add some randomness to the direction.
    direction += rand_range(-PI / 4, PI / 4)
    mob.rotation = direction
    # Set the velocity (speed & direction).
    mob.linear_velocity = Vector2(rand_range(mob.min_speed, mob.max_speed), 0)
    mob.linear_velocity = mob.linear_velocity.rotated(direction)

4. 테스트

func _ready():
    randomize()
    new_game()


플레이어 이동, 몹 생성, 충돌시 사라지기가 정상 작동되면 다음 HUD 구성을 위해 new_game()부분은 제거해줍니다.

 

- Main Scene 끝 -

반응형

+ Recent posts