I'm working on a game where a level is separated into rooms where the camera is confined into the current room, meaning the camera wont "bleed" into adjacent ones. A room is a scene RoomBase consisting of Positions RoomLimitTopLeft and RoomLimitBottomRight (which define the camera's limits) and an Area2D which detects when the player enters the room. As each room's size and exits will wary, I created a script which streches the Area2D's CollisionShape to the rooms's size.
RoomBase.gd
const ROOM_TRANS_LIMIT = 16
onready var limit_tl = $RoomLimitTopLeft # Position
onready var limit_br = $RoomLimitBottomRight # Position
onready var room_transition = $RoomTransition # Area2D
onready var room_transition_coll = $RoomTransition/CollisionShape2D
func setRoomTransition():
var width = limit_br.position.x - limit_tl.position.x - 2*ROOM_TRANS_LIMIT
var height = limit_br.position.y - limit_tl.position.y - 2*ROOM_TRANS_LIMIT
self.room_transition.position = Vector2(limit_br.position.x/2, limit_br.position.y/2)
self.room_transition_coll.shape.set_extents(Vector2(width/2, height/2))
This code centers the Area2D's position to its room and stretches its collision to cover almost the whole room, which works fine with only one room. However, if a level consists of multiple rooms, the most recent room instance overwrites the collision shape of the previous ones. For example, if Room 1 is horizontal and Room 2 is vertical, then Room 1 will share 2's vertical collision shape.
Is it possible to change an individual scene instances collisions without affecting any others?
you could also change the setting of the node, if possible, in the Inspector
I'm not sure if this is the issue, but for what I understand you are using the same Shape2D for every room. If all they are all using the same Shape2D, and you modify that Shape2D, the changes are reflected in all of them.
You can duplicate the Shape2D from code (or make it unique from the inspector). That way you have a different Shape2D.
Related
I am trying to get my rock.png to move to the side(+x axis) when my mouse is moving. You can see that _target is the position of the event and the event is the mouse moving.
I then got the node image and set it to a variable.
In the else statement I made the rock.position the position of the _target and gave it somee space away from the _target
I want this to move because my camera moves and I want it to move with the flow of the camera
``
extends Camera2D
const zone = 10
onready var rock = get_node("rocks_png_1")
func _input(event: InputEvent) -> void:
if event is InputEventMouseMotion:
var _target = event.position
if _target.length() < zone:
self.position = Vector2(640,350)
else:
self.position = _target.normalized() * (_target.length() - zone) * 0.5
rock.position = Vector2(int(_target)+40, int(_target)+20)
``
From the code I used above I get this error
Invalid get Index 'position' (on base: 'TextureRact')
I tried just using the same code as I used in my self.position for the camera that made it move, but when I try it for the rock.position it gives me an error that tells me I need a Vector?
Invalid get Index 'position' (on base: 'TextureRact')
The error is telling you that TextureRect does not have a position property.
What happens is that a TextureRect is a Control which are positioned differently from Node2D (Camera2D is a Node2D). You can try using rect_position with it. Although I think you would be better off using a Sprite instead of a TextureRect (Sprite is a Node2D).
Notice that your TextureRect is a child of the Camera2D in the scene tree. Well, a Node2D would move with its parent automatically. So changing it to Sprite would negate the need of the line of code you are using to move it.
… Actually, due to the way Camera2D works (it has drag and limits) you might still want do something (depending what your goal is). So, know that the get_camera_screen_center method will give you the actual visual center of the screen (which is not the target of the Camera2D, again due to drag and limits).
I created a new path2d following the instructions in the my first game article: http://docs.godotengine.org/en/3.0/getting_started/step_by_step/your_first_game.html
I wanted to move the "box" on screen so that I could see how the mobs spawn in, but when I ran the scene, it stayed off screen.
I created a new path2d, centered this one in the middle of the screen, and it works like I wanted it to, but now I moving this one in the editor doesn't update the position in game.
What's going on?
Thanks
func _on_mobtimer_timeout():
$mobtimer.wait_time = 0.1 + randf() / 2
$mobspawn/moblocation.set_offset(randi())
var mob = Mob.instance()
add_child(mob)
var direction = $mobspawn/moblocation.rotation + PI/2
mob.position = $mobspawn/moblocation.position
direction += rand_range(-PI/8, PI/8)
mob.rotation = direction
mob.set_linear_velocity(Vector2(rand_range(200, 200 + score * 30), 0).rotated(direction))
A Node2D's position property is relative to it's parent's position. The code from the Dodge The Creeps tutorial assumes that MobPath is located at 0, 0 and fails when that assumption is false.
In your case you are taking a MobSpawnLocation's position relative to MobPath and then setting it as the new Mob's global position.
Luckily Node2D's have another property that we can use in these circumstances global_position. It can be used like this:
mob.position = $mobspawn/moblocation.global_position
http://docs.godotengine.org/en/stable/classes/class_node2d.html#member-variables
This isn't a full solution, but I found a weird workaround. Instead of changing the position in the editor, if you use the nodes on the orange box (at the intersection of orange and blue), you can kind of alternate to move the box around.
How would I go about changing the registration point of a movieclip labeled "tablet" placed on the stage (root) dynamically?
For example: I have the following:
var tablet = this.tablet; //movieclip labeled "tablet" on stage
function resetTablet(){
tablet.regX = tablet.width/2; //move registration point to center
tablet.regY = tablet.height/2;
}
However when I call it using GSAP:
var tl = new TimelineLite();
tl.to(tablet, 1, {alpha:1, onComplete:resetTablet})
.to(tablet, 3, {alpha:0, scaleX:1.5, scaleY:1.5})
the registration point is still set to the upper left corner rather than the center.
What am I doing wrong here? Thanks!
Registration points affect change both the transformation point, but also the position. If you set a displayobject that is 100x100 pixels to regX=50;regY=50, then it will draw from that point, moving the content 50px to the top and left. If you make that change you should also translate the clip to x=50;y=50.
An issue with you example is that there is no width or height on EaselJS content (explained here). You can get the bounds of anything generated by Flash CC using the nominalBounds property, which Flash exports as a property on every object. If you have multiple frames, you can turn on "multi-frame bounds" in the publish settings, and a frameBounds property is added to the objects as well.
Note that nominalBounds and frameBounds are not used by the getBounds method.
Here is how you might be able to approach it.
var bounds = tablet.nominalBounds;
tablet.regX = bounds.width/2;
tablet.regY = bounds.height/2;
// Optional if your actual registration point was [0,0] before:
tablet.x += tablet.regX;
tablet.y += tablet.regX;
Hope that helps.
There is a too long, didn't read version down below.
So I've been making a little game in which the player has to click on a grid of bricks that matches the color of the needed brick in the upper right hand corner of the screen. After they click on the needed color, the bricks explode and the bricks of the same color next to them explode as well creating combos. That leaves holes in the grid so I have to somehow reset the grid itself without resetting the gamestate itself. I've got something working right now which is this:
private function ResetNow():Void
{
if (Restter == 1) Restter = 0;
//if this block is up here, same results
/*
wantedBricks.kill();
wantedBrik._changeColor = FlxMath.rand(0, 2);
bricks.autoReviveMembers = true;
bricks.revive();
*/
Restter = 0;
//Removes stray detectors so the neverending combo bug won't occur
for (stray in dets.members) stray.kill();
if (Restter == 0)
{
wantedBricks.kill();
wantedBrik._changeColor = FlxMath.rand(0, 2);
bricks.autoReviveMembers = true;
bricks.revive();
wantedBricks.autoReviveMembers = true;
wantedBricks.revive();
for (zgem in bricks.members) zgem.EQUITYCHECK = FlxMath.rand(0, 2);
}
//add(bricks);
Restter = 1;
}
So, again, I have a grid of blocks set up at create, that is group bricks. And I have a sprite in the upper right corner which is wantedBrik. What happens during gameplay, is the player clicks on the bricks that matches the wanted bricks to clear them out of the grid. When there are no more wantedBricks(a group), it is supposed to reset the grid, and change the color of the wantedBrik. I also have it somewhere else in the code that if a member of the big grid's EQUITYCHECK(basic object hacked in value) is equal to the wantedBrik, add it to the wantedBricks(which, is why I'm checking for no more of them). So, what happens?
Well, if the color of the wantedBrik doesn't change, everything's fine and resets like normal. the wantedBricks group acurately counts the bricks that actually match the wantedBrik's color. And when it does change, for some reason, gameplay is normal. BUT, wantedBricks not only thinks that the old color is still needed, but it also thinks the new color is still needed too. So when the player clicks the new needed color bricks, they do explode, but because wantedBrik thinks the old color is still wanted, it doesn't hit null and the grid won't reset.
What can I do to make sure that wantedBricks behaves correctly after a color change?
TL;DR version: I need to get a Haxe array to forget or lose old numbers. How can I do this?
The "Pirate Pig" sample may be useful to you. Since it is a puzzle game, there may be some similar problems that were solved there. You can find it using openfl create or nme create depending on which you are currently using.
You can create a simple array like this:
var myArray = [];
You can also type arrays, like this:
var numbers = new Array<Float>();
Then you can use push(), concat() and other array methods.
I am using node.js and express, and I am calling server-side functions and syncing variables using nowjs. Suppose the user is drawn as a sprite on the canvas. His x,y coordinates are kept server-side in a "position" array.
Server-side:
position = { x : 0; y : 0 }
updatePosition = function (a,b)
{
playerPosition.x += a;
playerPosition.y += b;
}
Client-side:
if keypress('right'){ updatePosition(32,0); }
These are pseudocode. When the user presses the 'right' button, the server-side "updatePosition" function is called, which adds 32 (pixels) to the x-coordinate of the "position" array. This array is then shared with the client, and the new position is drawn on the canvas using client-side function.
Suppose I don't want to draw the sprite at the new position instantly. I want to play a walking animation that gradually moves the sprite 32 pixels to the right, and takes say 1 second to complete. I might implement it this way:
User presses the 'right' button.
The animation starts playing client-side.
updatePosition is called server-side as usual.
When animation on the client finishes, check if the final position client-side matches the coordinates stored server side.
When the user presses the 'right' button/key, he cannot repeat the keypress until 1 second later. The 1 second long "walking" animation has to complete and final position checked with the server-side coordinates before he can press 'right' again to move his sprite.
Question: How do I keep track of the 1 second server side? I can't do it client-side because the user will be able to hack his client to reduce the animation time.
Is the solution to "timestamp" the position array? E.g. position = { x : 0; y : 0, time: 0 }. If the user presses the 'right' button again, the server would check to see if the last position update was greater than 1 second ago. If less than 1 second, the server ignores it.
Why not simply storing a "lock" in the user session?
session.editLock = new Date().getTime();
When another edit is triggered by the client, just:
if(session.editLock && new Date().getTime() - session.editLock > 1000) {
// Return error
}
Modifying the position object doesn't feel right to me. A position object is meant to store position, not time.